#include <Windows.h>
#include "filesystem.h"

#pragma warning(disable : 4995) //funcation was marked as deprecated

//----------------------------------------------------------------------------
// ListAllFilesInDirectory
// creates a list of all the file names in the given directory.
//
// @param dirName
//		the directory name to list its files 
//		(can be a relative name or an absolute name)
// @returm
//		a pointer to a list of strings. 
//		each string in the list is a file name in the given directory. 
//		(the list includes the "." and ".." file names)
//		in case of a failure NULL pointer is returned.
//		note: this function allocates memory for the list it is the responsibility
//		of the caller to free this memory.
//
// @throws bad_alloc
//		in case memory allocation failed.
//----------------------------------------------------------------------------
list<string>* WinFileSystem::ListAllFilesInDirectory(string dirName)
{
	WIN32_FIND_DATA ffd;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	DWORD dwError=0;

	string currentDir = GetTheCurrentDirectory();

	if (!SetTheCurrentDirectory(dirName))
		return NULL;
   
	// Find the first file in the directory.
	hFind = FindFirstFile("*.*", &ffd);
	if (INVALID_HANDLE_VALUE == hFind) 
	{
		return NULL;
	} 
   
	// make a list of all the files in the directory
	list<string> *fileNames = NULL;
	try
	{
		fileNames = new list<string>();
	}
	catch(std::bad_alloc *e)
	{
		e = NULL;
		SetTheCurrentDirectory(currentDir);
		return NULL;
	}

	do
	{  
		string fileName = ffd.cFileName;	 
		fileNames->push_front(fileName);	  
	}
	while (FindNextFile(hFind, &ffd) != 0);
 
	dwError = GetLastError();
	if (dwError != ERROR_NO_MORE_FILES) 
	{
		delete fileNames;
		SetTheCurrentDirectory(currentDir);
		return NULL; // the listing was problematic, no files were collected.
	}

	SetTheCurrentDirectory(currentDir);

	FindClose(hFind);
	return fileNames;
}

//----------------------------------------------------------------------------
// MakeDirectory
// creates a new directory with the given name
//
// @param dirName
//		the name of the directory to create.
//		(can be a relative name or an absolute name)
//
// @return bool
//		true  - if the directory was created
//		false - if not 
//		(note: if the directory already exists returns false)
//----------------------------------------------------------------------------
bool WinFileSystem::MakeDirectory(string dirName)
{
	return (CreateDirectory(dirName.c_str(),NULL) != 0 ? true : false);
}

//----------------------------------------------------------------------------
// NavigateUpFromCurrentDirectory
// navigates up in the directory hierarchy tree as many levels as specified
// starting at the current directory.
//
// @param numberOfLevels
//		the number of levels to go up from the current directory.
//
// @return bool
//		true  - if successfully went up numberOfLevels from current directory
//		false - if a problem occurred
//----------------------------------------------------------------------------
bool WinFileSystem::NavigateUpFromCurrentDirectory(int numberOfLevels)
{
	string newDirectoryPath = GetTheCurrentDirectory();
	
	if(newDirectoryPath.compare("") == 0)
		return false;

	int pos = newDirectoryPath.size() - 1;
	for(int i=0; i<numberOfLevels; i++)
	{
		pos = newDirectoryPath.find_last_of('\\', pos-1);
	}

	newDirectoryPath = newDirectoryPath.substr(0, pos);
	
	return SetTheCurrentDirectory(newDirectoryPath);
}

//----------------------------------------------------------------------------
// GetTheCurrentDirectory
// returns the full path and name of the current directory.
//
// @return string
//		the string of the full name (absolute path + directory name) 
//		of the current directory.
//		note:	if the path returned is not an empty string, 
//				then the path ends with a '\'
//		in case of an error an empty string is returned.
//----------------------------------------------------------------------------
string WinFileSystem::GetTheCurrentDirectory()
{
	string path = "";
	char currentPath[MAX_PATH] = "";
	int pathLength = GetCurrentDirectory(MAX_PATH, currentPath);
	if (pathLength > MAX_PATH)
	{
		char *longCurrentPath = NULL;
		try
		{
			longCurrentPath = new char[pathLength + 2];
		}
		catch(std::bad_alloc *e)
		{
			e=NULL;
			return path;
		}
		pathLength = GetCurrentDirectory(pathLength + 2, longCurrentPath);
		path = longCurrentPath;
		delete longCurrentPath;
		return path;
	}
	else if( pathLength > 0 )
	{
		path = currentPath;
	}

	return path;
}

//----------------------------------------------------------------------------
// SetTheCurrentDirectory
// sets the current directory to be the directory specified.
//
// @param newDir
//		the new directory to set as the current directory
//		(can be a relative name or an absolute name)
//
// @return bool
//		true if the new current directory is the directory specified
//		false if not
//----------------------------------------------------------------------------
bool WinFileSystem::SetTheCurrentDirectory(string newDir)
{
	return (SetCurrentDirectory(newDir.c_str()) != 0 ? true : false);
}

//----------------------------------------------------------------------------
// IsFileExsits
// checks if a given file name exists or not
//
// @param fileName
//		the name of the file to look for
//		(can be a relative name or an absolute name)
//
// @return bool
//		true if the file exists
//		false if it was not found
//----------------------------------------------------------------------------
bool WinFileSystem::IsFileExsits(string fileName)
{
	WIN32_FIND_DATA ffd;
	HANDLE hFind = INVALID_HANDLE_VALUE;
   
	// Find the file in the directory.
	hFind = FindFirstFile(fileName.c_str(), &ffd);
	if (INVALID_HANDLE_VALUE == hFind) 
	{
		return false;
	} 
	
	return true;
}